﻿#ifdef LINUX

#include "Network/TCPServer.h"
#include "Network/TCPClient.h"
#include "Async/PackagedTask.h"


#include "Platform/Socket/SocketPlatform.h"

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>

//memset
#include <cstring>

bool CTCPServer::IsPortOccupied(const SIPAddress& IP,uint16_t Port)
{
    int32_t s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s < 0)
    {
        return true;
    }

    sockaddr_in Service;
    Service.sin_family = AF_INET;
    Service.sin_port = htons(Port);
    if (IP.IsIPv6())
    {
        memcpy(&Service.sin_addr, IP.IP.IPv6, sizeof(IP.IP.IPv6));
    }
    else
    {
        memcpy(&Service.sin_addr, IP.IP.IPv4, sizeof(IP.IP.IPv4));
    }

    if (bind(s, (sockaddr *)&Service, sizeof(Service)) < 0)
    {
        close(s);
        return true;
    }

    close(s);
    return false;

}


void CTCPServer::Listen(const SIPAddress& IP, uint16_t Port)
{
    std::lock_guard<std::mutex> Lock(ListenSocketMutex);
    if(State!=ETCPServerState::Idle)
    {
        //当前TCP服务器状态不是空闲状态,不能再次监听
        OnErrorOccured.ExecuteIfBound(ETCPServerError::CreateSocketWhenListeningError);
        return;
    }

    //创建socket,use Linux api
    PlatformData->Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (PlatformData->Socket < 0)
    {
        OnErrorOccured.ExecuteIfBound(ETCPServerError::CreateSocketError);
        return;
    }

    //绑定socket
    sockaddr_in Service;
    Service.sin_family = AF_INET;
    Service.sin_port = htons(Port);
    if (IP.IsIPv6())
    {
        memcpy(&Service.sin_addr, IP.IP.IPv6, sizeof(IP.IP.IPv6));
    }
    else
    {
        memcpy(&Service.sin_addr, IP.IP.IPv4, sizeof(IP.IP.IPv4));
    }

    if (bind(PlatformData->Socket, (sockaddr *)&Service, sizeof(Service))  < 0)
    {
        close(PlatformData->Socket);
        //绑定socket失败
        OnErrorOccured.ExecuteIfBound(ETCPServerError::BindAddressAndPortError);
        return;
    }
   

    //开始监听
    if (listen(PlatformData->Socket, SOMAXCONN) < 0)
    {
        close(PlatformData->Socket);
        //listen失败
        OnErrorOccured.ExecuteIfBound(ETCPServerError::ListenError);
        return;
    }

    //设置为非阻塞
    int Flags = fcntl(PlatformData->Socket, F_GETFL, 0);
    fcntl(PlatformData->Socket, F_SETFL, Flags | O_NONBLOCK);

    State=ETCPServerState::Listening;

    StartAcceptTask();
}


void CTCPServer::StartAcceptTask()
{
    TThreadSafeWeakPtr<CTCPServer> This=AsShared();

    std::shared_ptr<CPackagedTask<void>> 
        AcceptTask = WH::CreateAsyncTask<void>(
        [This](bool& )mutable ->void
    {
        auto _This=This.Lock();
        if(!_This)
        {
            return;
        }

        int32_t ClientSocket;
        {
            std::lock_guard<std::mutex> Lock(_This->ListenSocketMutex);
            if(_This->State!=ETCPServerState::Listening)
            {
                //socket已经关闭
                return;
            }

            sockaddr_in addr;
            int32_t addrLen = sizeof(addr);
            ClientSocket = accept(_This->PlatformData->Socket, (sockaddr*)&addr, (socklen_t*)&addrLen);

        }

        if(ClientSocket<0)
        {
            //没有客户端连接
            _This->StartAcceptTask();
            return;
        }

        {
            std::lock_guard<std::mutex> Lock(_This->PendingAcceptSocketsMutex);
            CSocketPlatformData * NewData = new CSocketPlatformData();
            NewData->Socket=ClientSocket;
            _This->PendingAcceptSockets.push(NewData);
        }

        //继续接受下一个客户端
        _This->StartAcceptTask();

        //通知客户端连接成功,
        //之所以放在StartAcceptTask()之后是因为这个操作可能会比较耗时
        //可能影响下一次accept
        _This->OnClientConnected.ExecuteIfBound();

    });        

    AcceptTask->Start();
    
}


void CTCPServer::StopListen()
{
    if(State!=ETCPServerState::Listening)
    {
        return;
    }

    //关闭socket
    {
        std::lock_guard<std::mutex> Lock(ListenSocketMutex);
        close(PlatformData->Socket);
        PlatformData->Socket=-1;
        State=ETCPServerState::Idle;
    }

    //清空待处理的socket
    {
        std::lock_guard<std::mutex> Lock(PendingAcceptSocketsMutex);
        while(!PendingAcceptSockets.empty())
        {
            auto Data=PendingAcceptSockets.front();
            PendingAcceptSockets.pop();
            close(Data->Socket);
            delete Data;
        }
    }

}


#endif